// --------------------------------------------------------------------------------------------------------------------- 
// <copyright file="ModelBase.cs" company="Scrum for Team System">
//   None
// </copyright>
// <summary>
//   Defines the ModelBase type.
// </summary>
// ---------------------------------------------------------------------------------------------------------------------
namespace ScrumForTeamSystem.Metrics
{
    using System.Collections.Generic;
    using System.Globalization;

    /// <summary>
    /// Base class for the different forecasting models available.
    /// </summary>
    internal abstract class ModelBase
    {
        /// <summary>
        /// Gets a value indicating whether this instance is adjusted to move vertically so that it passes through the last Data point.
        /// </summary>
        /// <value>
        /// <c>true</c> if this instance is adjusted; otherwise, <c>false</c>.
        /// </value>
        public bool IsAdjusted { get; private set;  }

        /// <summary>
        /// Gets or sets the Adjustment.
        /// </summary>
        /// <value>The Adjustment.</value>
        protected double Adjustment { get; set; }

        /// <summary>
        /// Gets or sets the PointCount.
        /// </summary>
        /// <value>The PointCount.</value>
        protected int PointCount { get; set; }

        /// <summary>
        /// Gets the Data.
        /// </summary>
        /// <value>The Data values.</value>
        protected IList<double?> Data { get; private set; }

        /// <summary>
        /// Gets a single point on the Trend line. Null is returned if the Trend line is not to be drawn for this position.
        /// </summary>
        /// <returns>
        /// Null (subclasses may return a Trend line point).
        /// </returns>
        public abstract double? GetNextTrendValue();

        /// <summary>
        /// Initialises the model.
        /// </summary>
        /// <param name="isAdjusted">if set to <c>true</c> [is adjusted].</param>
        /// <param name="concatenatedBurndown">The concatenated burndown.</param>
        /// <returns>The initialised Trend model.</returns>
        public ModelBase InitialiseModel(bool isAdjusted, string concatenatedBurndown)
        {
            this.IsAdjusted = isAdjusted;
            this.SplitBurndowns(concatenatedBurndown);
            this.CalculateTrend();
            this.PointCount = 0;

            return this;
        }

        /// <summary>
        /// Overridden in subclasses to calculate a Trend line.
        /// </summary>
        protected abstract void CalculateTrend();

        /// <summary>
        /// Split a concatenated string of values up, and parse the values into the Data array.
        /// </summary>
        /// <param name="concat">CSV string of values.</param>
        private void SplitBurndowns(string concat)
        {
            var burndowns = concat.Split(new[] { ',' });

            this.Data = new List<double?>();

            foreach (var burndown in burndowns)
            {
                double burndownValue;
                if (!string.IsNullOrEmpty(burndown) && double.TryParse(burndown, NumberStyles.Any, CultureInfo.CurrentCulture, out burndownValue))
                {
                    this.Data.Add(burndownValue);
                    this.PointCount++;
                }
                else
                {
                    this.Data.Add(null);
                }
            }
        }
    }
}